

/**
 * 基于分状态 计算一个需要缓存的值
 * @param {*} selectors 选择器数组 选择器里面的每个值都是一个函数 接收 state 总状态作为参数 返回分状态
 * @param {*} reducer 函数 依次接收选择器数据中的分状态 返回一个需要缓存的值
 * @returns 返回一个记忆函数 记忆函数接收分状态作为参数 返回分状态计算后缓存的值
 */
export default function createSelector(selectors, reducer) {
  let lastState; // 用于缓存上一次总状态
  let lastValue; // 用于缓存上一次总状态计算的值

  return function (state) {
    // 当前传递的 state 总状态与上一次 总状态 如果一致 则使用上次缓存的值
    if (shallowEqual(state, lastState)) {
      return lastValue
    }
    let values = selectors.map(selector => selector(state))
    lastValue = reducer(...values)
    lastState = state
    return lastValue
  }
}

/**
 * 浅比较两个对象 判断是否相等
 */
function shallowEqual(objA, objB) {
  if(objA === objB) return true

  // 只要有一项成立 则直接认为两个不相等
  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false
  }

  // 获取自身可枚举的属性
  const keysA = Object.keys(objA)
  const keysB = Object.keys(objB)

  // 两者属性数量不一致 直接认为两个不相等
  if (keysA.length !== keysB.length) return false

  // 遍历 objA 的每个属性名
  for (let i = 0; i < keysA.length; i++) {
    // 如果 objB 对象的自有属性没有 则也认为这两个对象不相等
    // 两个对象中的相同属性名的值不相等 则认为这两个对象不相等
    if (
      !Object.prototype.hasOwnProperty.call(objB, i) || objA[i] !== objB[i]
    ) {
      return false
    }
  }

  return true
}
